/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.sql.ResultSet;

import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * @author Clinton Begin
 */
/**
 * 参数映射
 * 
 */
public class ParameterMapping {
  /**
   * 配置
   */
  private Configuration configuration;

  //例子：#{property,javaType=int,jdbcType=NUMERIC}
  
  /**
   * 参数属性,例:property
   */
  private String property;
  /**
   * 参数模式，例:mode,----存储过程时用的
   */
  private ParameterMode mode;
  /**
   * java类型,例:javaType=int
   */
  private Class<?> javaType = Object.class;
  /** 
   * jdbc类型,例:jdbcType=NUMERIC
   */
  private JdbcType jdbcType;
  //numericScale
  /**
   * 数值比例，例如:数值类型，还有一个小数保留位数的设置，来确定小数点后保留的位数,如:#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
   */
  private Integer numericScale;
  /**
   * 类型处理器
   */
  private TypeHandler<?> typeHandler;
  /**
   * 结果MapId
   */
  private String resultMapId;
  /**
   * jdbc类型名字,例:jdbcType=NUMERIC
   */
  private String jdbcTypeName;
  /**
   * 表达式
   */
  private String expression;

  private ParameterMapping() {
  }

  /**
   * 静态内部类，建造者模式
   *
   */
  public static class Builder {
    private ParameterMapping parameterMapping = new ParameterMapping();
    /**
     * 创建ParameterMapping
     * @param configuration 配置
     * @param property 属性
     * @param typeHandler 类型处理器
     */
    public Builder(Configuration configuration, String property, TypeHandler<?> typeHandler) {
      parameterMapping.configuration = configuration;
      parameterMapping.property = property;
      parameterMapping.typeHandler = typeHandler;
      parameterMapping.mode = ParameterMode.IN;
    }
    /**
     * 创建ParameterMapping
     * 
     * @param configuration 配置
     * @param property 属性
     * @param javaType java类型
     */
    public Builder(Configuration configuration, String property, Class<?> javaType) {
      parameterMapping.configuration = configuration;
      parameterMapping.property = property;
      parameterMapping.javaType = javaType;
      parameterMapping.mode = ParameterMode.IN;
    }
    /**
     * 构建mode
     * @param mode 
     * @return
     */
    public Builder mode(ParameterMode mode) {
      parameterMapping.mode = mode;
      return this;
    }
    /**
     * 构建java类型
     * @param javaType
     * @return
     */
    public Builder javaType(Class<?> javaType) {
      parameterMapping.javaType = javaType;
      return this;
    }
    /**
     * 构建jdbc类型
     * @param jdbcType
     * @return
     */
    public Builder jdbcType(JdbcType jdbcType) {
      parameterMapping.jdbcType = jdbcType;
      return this;
    }
    /**
     * 构建数值比例
     * @param numericScale
     * @return
     */
    public Builder numericScale(Integer numericScale) {
      parameterMapping.numericScale = numericScale;
      return this;
    }
    /**
     * 构建结果MapId
     * @param resultMapId
     * @return
     */
    public Builder resultMapId(String resultMapId) {
      parameterMapping.resultMapId = resultMapId;
      return this;
    }
    /**
     * 构建类型处理器
     * @param typeHandler
     * @return
     */
    public Builder typeHandler(TypeHandler<?> typeHandler) {
      parameterMapping.typeHandler = typeHandler;
      return this;
    }
    /**
     * 构建jdbc类型名字
     * @param jdbcTypeName 
     * @return
     */
    public Builder jdbcTypeName(String jdbcTypeName) {
      parameterMapping.jdbcTypeName = jdbcTypeName;
      return this;
    }
    /**
     * 构建表达式
     * @param expression
     * @return
     */
    public Builder expression(String expression) {
      parameterMapping.expression = expression;
      return this;
    }
    /**
     * 构建parameterMapping
     * @return
     */
    public ParameterMapping build() {
      resolveTypeHandler();
      validate();
      return parameterMapping;
    }
    /**
     * 校验
     */
    private void validate() {
     //判断参数类型是否为ResultSet
      if (ResultSet.class.equals(parameterMapping.javaType)) {
          //判断是否为空
    	  if (parameterMapping.resultMapId == null) { 
          throw new IllegalStateException("Missing resultmap in property '"  
              + parameterMapping.property + "'.  " 
              + "Parameters of type java.sql.ResultSet require a resultmap.");
        }            
      } else {
    	//判断类型处理器是否为空
        if (parameterMapping.typeHandler == null) { 
          throw new IllegalStateException("Type handler was null on parameter mapping for property '"  
              + parameterMapping.property + "'.  " 
              + "It was either not specified and/or could not be found for the javaType / jdbcType combination specified.");
        }
      }
    }
    /**
     * 解析类型处理器
     */
    private void resolveTypeHandler() {
        //如果没有指定特殊的typeHandler，则根据javaType，jdbcType来查表确定一个默认的typeHandler
      if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {
        Configuration configuration = parameterMapping.configuration;
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
      }
    }

  }
  /**
   * 得到参数属性
   * @return
   */
  public String getProperty() {
    return property;
  }

  /**
   * Used for handling output of callable statements(用于处理可调用语句的输出)
   * 得到mode
   * @return
   */
  public ParameterMode getMode() {
    return mode;
  }

  /**
   * Used for handling output of callable statements
   * 得到java类型
   * @return
   */
  public Class<?> getJavaType() {
    return javaType;
  }

  /**
   * Used in the UnknownTypeHandler in case there is no handler for the property type
   * 得到jdbc类型
   * @return
   */
  public JdbcType getJdbcType() {
    return jdbcType;
  }

  /**
   * Used for handling output of callable statements
   * 得到数值比例
   * @return
   */
  public Integer getNumericScale() {
    return numericScale;
  }

  /**
   * Used when setting parameters to the PreparedStatement
   * 得到类型处理器
   * @return
   */
  public TypeHandler<?> getTypeHandler() {
    return typeHandler;
  }

  /**
   * Used for handling output of callable statements
   * 得到结果MapId
   * @return
   */
  public String getResultMapId() {
    return resultMapId;
  }

  /**
   * Used for handling output of callable statements
   * jdbc类型名字
   * @return
   */
  public String getJdbcTypeName() {
    return jdbcTypeName;
  }

  /**
   * Not used
   * 得到表达式
   * @return
   */
  public String getExpression() {
    return expression;
  }

}
